/**
 * ***************************************************************
 * JADE - Java Agent DEvelopment Framework is a framework to develop multi-agent
 * systems in compliance with the FIPA specifications. Copyright (C) 2000 CSELT
 * S.p.A. * GNU Lesser General Public License
 *
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation, version 2.1 of the License. * This library is
 * distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 * ***************************************************************
 */
package BookTrading;

import jade.core.Agent;
import jade.core.AID;
import jade.core.behaviours.*;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;
import jade.domain.DFService;
import jade.domain.FIPAException;
import jade.domain.FIPAAgentManagement.DFAgentDescription;
import jade.domain.FIPAAgentManagement.ServiceDescription;
import jade.lang.acl.UnreadableException;
import java.util.Hashtable;

import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;

public class BookBuyerAgent extends Agent {

    // The title of the book to buy
    private String targetBookTitle;
    // The list of known seller agents
    private AID[] sellerAgents;
    private Hashtable catalogue_buyer;
    private BookBuyerGui myGui;
    ;
    private BookBuyerAgent buyerAgent;
    private BookObject bookobject;

    // Put agent initializations here
    protected void setup() {
        // Printout a welcome message
        System.out.println("Bienvenue! Buyer-agent " + getAID().getName() + " is ready.");

        // Create the catalogue
        catalogue_buyer = new Hashtable();

        // Register the book-selling service in the yellow pages
        DFAgentDescription dfd = new DFAgentDescription();
        dfd.setName(getAID());
        ServiceDescription sd = new ServiceDescription();
        sd.setType("book-buyer");
        sd.setName("JADE-book-trading-seller");
        dfd.addServices(sd);
        try {
            DFService.register(this, dfd);
        } catch (FIPAException fe) {
            fe.printStackTrace();
        }
        buyerAgent = this;
        // Create and show the GUI 
        //myGui1 = new BookBuyerGui(this);
        System.out.println("Nous sommes ici ");
        addBehaviour(new ReceiveRequestFromEnchere());

        // Get the title of the book to buy as a start-up argument
//        Object[] args = getArguments();
//        if (args != null && args.length > 0) {
//            targetBookTitle = (String) args[0];
//            System.out.println("Target book is " + targetBookTitle);
//
//            // Add a TickerBehaviour that schedules a request to seller agents every 10 secondes
//            addBehaviour(new TickerBehaviour(this, 10000) {
//                protected void onTick() {
//                    // Update the list of seller agents
//                    DFAgentDescription template = new DFAgentDescription();
//                    ServiceDescription sd = new ServiceDescription();
//                    sd.setType("book-selling");
//                    template.addServices(sd);
//                    try {
//                        DFAgentDescription[] result = DFService.search(myAgent, template);
//                        System.out.println("Found the following seller agents:");
//                        sellerAgents = new AID[result.length];
//
//                        if (result.length > 0) {
//                            sellerAgents[0] = result[0].getName();
//                            System.out.println(sellerAgents[0].getName());
//                        }
//                    } catch (FIPAException fe) {
//                        fe.printStackTrace();
//                    }
//                   // myAgent.addBehaviour(new GetObjectOfSeller());
//                    myAgent.addBehaviour(new ReceiveRequestFromEnchere());
//                }
//            });
//        }
//        else {
//			// Make the agent terminate
//			System.out.println("No target object specified");
//			doDelete();
//		}
    }

    private class ReceiveRequestFromEnchere extends CyclicBehaviour {

        @Override
        public void action() {
            MessageTemplate mt = MessageTemplate.MatchPerformative(ACLMessage.CFP);
            ACLMessage msg = myAgent.receive(mt);
            if (msg != null) {
                // CFP Message received. Process it

                bookobject = new BookObject();
                try {
                    bookobject = (BookObject) msg.getContentObject();
                    System.out.println("BookObject" + bookobject.getName());

                } catch (UnreadableException ex) {
                    Logger.getLogger(BookBuyerAgent.class.getName()).log(Level.SEVERE, null, ex);
                }
                ACLMessage reply = msg.createReply();
                if (bookobject != null) {
                    //create GUI
                    System.out.println("BookObject is not null");
                    myGui = new BookBuyerGui(bookobject);
                    myGui.showGui();

                    // The requested book is available for sale. Reply with the price
                    reply.setPerformative(ACLMessage.PROPOSE);
                    reply.setContent("OK");

                    //reply.setContent(String.valueOf(price.intValue()));
                } else {
                    // The requested book is NOT available for sale.
                    reply.setPerformative(ACLMessage.REFUSE);
                    reply.setContent("not-available");
                }
                myAgent.send(reply);
            } else {
                block();
            }
        }
    }  // End of inner class OfferRequestsServer

    private class GetObjectOfSeller extends Behaviour {

        private AID seller; // The agent who provides the best offer 
        private int bestPrice;  // The best offered price
        private int repliesCnt = 0; // The counter of replies from seller agents
        private MessageTemplate mt; // The template to receive replies
        private int step = 0;

        @Override
        public void action() {
            System.out.println("GetObjectOfSeller");
            //step = 0;
            switch (step) {
                case 0:
                    System.out.println("Case 0");
                    // Send the cfp to all sellers
                    ACLMessage cfp = new ACLMessage(ACLMessage.CFP);
                    for (int i = 0; i < sellerAgents.length; ++i) {
                        cfp.addReceiver(sellerAgents[i]);
                    }
                    cfp.setContent(targetBookTitle);
                    cfp.setConversationId("book-trade");
                    cfp.setReplyWith("cfp" + System.currentTimeMillis()); // Unique value
                    myAgent.send(cfp);
                    // Prepare the template to get proposals
                    mt = MessageTemplate.and(MessageTemplate.MatchConversationId("book-trade"),
                            MessageTemplate.MatchInReplyTo(cfp.getReplyWith()));
                    step = 1;

                    System.out.println("Step" + step);
                    break;
                case 1:
                    System.out.println("Case 1");
                    // Receive all ObjectBook from seller agents
                    ACLMessage reply = myAgent.receive(mt);
                    if (reply != null) {
                        System.out.println("Reply" + reply.getContent());
                        // Reply received
                        if (reply.getPerformative() == ACLMessage.PROPOSE) {
                            // This is an offer 
                            BookObject object;
                            try {
                                System.out.println("Pass 1");
                                Object a = reply.getContentObject();
                                System.out.println("Object " + a.toString());

                                object = (BookObject) reply.getContentObject();

                                System.out.println("Name: " + object.getName() + "Prix: " + object.getPrice());
//                                myGui1 = new BookBuyerGui(buyerAgent, object);
//                                myGui1.showGui();
                            } catch (UnreadableException ex) {
                                Logger.getLogger(BookBuyerAgent.class.getName()).log(Level.SEVERE, null, ex);
                            }
                        }
                    } else {
                        block();
                    }
                    break;
            }
        }

        @Override
        public boolean done() {
            //throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
            return false;
        }
    }

    // Put agent clean-up operations here
    protected void takeDown() {
        // Printout a dismissal message
        System.out.println("Buyer-agent " + getAID().getName() + " terminating.");
    }

    /**
     * This is invoked by the GUI when the user adds a new book for sale
     *
     * @param title
     * @param price
     */
    /**
     * This is invoked by the GUI when the user adds a new book for sale
     *
     * @param title
     * @param price
     */
    public void updateCatalogue(final String title, final int price) {
        addBehaviour(new OneShotBehaviour() {
            public void action() {
                catalogue_buyer.put(title, new Integer(price));
                System.out.println(title + " inserted into catalogue. Price = " + price);
            }
        });
    }

    /*
     Inner class RequestPerformer.
     This is the behaviour used by Book-buyer agents to request seller 
     agents the target book.
     */
    private class RequestPerformer extends Behaviour {

        private AID bestSeller; // The agent who provides the best offer 
        private int bestPrice;  // The best offered price
        private int repliesCnt = 0; // The counter of replies from seller agents
        private MessageTemplate mt; // The template to receive replies
        private int step = 0;

        public void action() {
            switch (step) {
                case 0:
                    // Send the cfp to all sellers
                    ACLMessage cfp = new ACLMessage(ACLMessage.CFP);
                    for (int i = 0; i < sellerAgents.length; ++i) {
                        cfp.addReceiver(sellerAgents[i]);
                    }
                    cfp.setContent(targetBookTitle);
                    cfp.setConversationId("book-trade");
                    cfp.setReplyWith("cfp" + System.currentTimeMillis()); // Unique value
                    myAgent.send(cfp);
                    // Prepare the template to get proposals
                    mt = MessageTemplate.and(MessageTemplate.MatchConversationId("book-trade"),
                            MessageTemplate.MatchInReplyTo(cfp.getReplyWith()));
                    step = 1;
                    break;
                case 1:
                    // Receive all proposals/refusals from seller agents
                    ACLMessage reply = myAgent.receive(mt);
                    if (reply != null) {
                        // Reply received
                        if (reply.getPerformative() == ACLMessage.PROPOSE) {
                            // This is an offer 
                            int price = Integer.parseInt(reply.getContent());
                            if (bestSeller == null || price < bestPrice) {
                                // This is the best offer at present
                                bestPrice = price;
                                bestSeller = reply.getSender();
                            }
                        }
                        repliesCnt++;
                        if (repliesCnt >= sellerAgents.length) {
                            // We received all replies
                            step = 2;
                        }
                    } else {
                        block();
                    }
                    break;
                case 2:
                    // Send the purchase order to the seller that provided the best offer
                    ACLMessage order = new ACLMessage(ACLMessage.ACCEPT_PROPOSAL);
                    order.addReceiver(bestSeller);
                    order.setContent(targetBookTitle);
                    order.setConversationId("book-trade");
                    order.setReplyWith("order" + System.currentTimeMillis());
                    myAgent.send(order);
                    // Prepare the template to get the purchase order reply
                    mt = MessageTemplate.and(MessageTemplate.MatchConversationId("book-trade"),
                            MessageTemplate.MatchInReplyTo(order.getReplyWith()));
                    step = 3;
                    break;
                case 3:
                    // Receive the purchase order reply
                    reply = myAgent.receive(mt);
                    if (reply != null) {
                        // Purchase order reply received
                        if (reply.getPerformative() == ACLMessage.INFORM) {
                            // Purchase successful. We can terminate
                            System.out.println(targetBookTitle + " successfully purchased from agent " + reply.getSender().getName());
                            System.out.println("Price = " + bestPrice);
                            myAgent.doDelete();
                        } else {
                            System.out.println("Attempt failed: requested book already sold.");
                        }

                        step = 4;
                    } else {
                        block();
                    }
                    break;
            }
        }

        public boolean done() {
            if (step == 2 && bestSeller == null) {
                System.out.println("Attempt failed: " + targetBookTitle + " not available for sale");
            }
            return ((step == 2 && bestSeller == null) || step == 4);
        }
    }  // End of inner class RequestPerformer*/
}
